<?php

// uses
class Agilet
{
    /**
     * container
     * @var registry
     */
    static protected $_registry = array();

    /**
     * protected app base url
     * @var string
     */
    static protected $_appUrl = APP_URL;

    /**
     * static base url liked to our media server
     * @var string
     */
    static protected $_staticUrl = APP_STATIC_URL;

    /**
     * @var string
     */
    static protected $_appDomain = APP_DOMAIN;

    /**
     * static base url liked to our media server
     * @var string
     */
    static protected $_mediaUrl = APP_MEDIA_URL;

    /**
     * @var Template
     */
    static protected $_template = null;

    /**
     * @var int
     */
    static protected $_appId = 1;

    /**
     * get current viewer of none.
     */
    static protected $_viewer = null;

    /**
     * get static base url
     * @return string
     */
    static public function getStaticUrl()
    {
        return self::$_staticUrl;
    }

    /**
     * set static base url
     * @param string $staticUrl
     * @return void
     */
    static public function setStaticUrl($staticUrl)
    {
        self::$_staticUrl = $staticUrl;
    }

    /**
     * @return string
     */
    static public function getAppUrl()
    {
        return self::$_appUrl;
    }

    /**
     * @param  string  $baseUrl
     * @return void
     */
    static public function setAppUrl($appUrl)
    {
        self::$_appUrl = $appUrl;
    }

    /**
     * @return string
     */
    static public function getMediaUrl()
    {
        return self::$_mediaUrl;
    }

    /**
     * @param  string  $baseUrl
     * @return void
     */
    static public function seMediaUrl($mediaUrl)
    {
        self::$_mediaUrl = $mediaUrl;
    }

    /**
     * rerieves a variable regiester to registry
     */
    static public function getRegistry($key, $default = null)
    {
        return isset(self::$_registry[$key]) ? self::$_registry[$key] : $default;
    }

    static public function setRegistry($key, $value)
    {
        self::$_registry[$key] = $value;
    }

    /**
     * load configuration file
     * it seems always return array
     * @return array
     */
    static public function loadConfig($file, $offset = null)
    {

        $data = null;

        if (file_exists($filename = SETTING_PATH . '/' . $file))
        {
            $data =
            include $filename;

        }
        else
        if (file_exists($filename = SYSTEM_SETTING_PATH . '/' . $file))
        {
            $data =
            include $filename;

        }
        else
        {
            throw new Exception("Invalid configuration file under config directory $filename");
        }

        if ($offset)
        {
            if (!isset($data[$offset]))
            {

                throw new Exception("invalid configuration offset $file:$offset");
            }
            return $data[$offset];
        }
        return $data;
    }

    static public function hasClass($class_name)
    {
        return class_exists($class_name) or self::__autoload($class_name);
    }

    /**
     * find class
     * @param string $class_name
     * @return true/false
     */
    static public function requireClass($path, $module = 'system')
    {
        return class_exists($class_name) or self::__autoload($class_name);
    }

    /**
     * factory a resource object
     *
     * @param      string     $name
     * @param      string     $ext
     * @return     Object
     */
    static public function __resource($name, $ext = null)
    {
        if (self::hasClass($class_name = self::sanitizeClass($name)))
        {
            return new $class_name;
        }

        throw new Exception("class $name $ext does not exists!");
    }

    /**
     * @param     string $name
     * @param     string $ext
     * @return    string class name
     */
    static public function sanitizeClass($name, $ext)
    {
        if ($ext)
        {
            $name = trim(str_replace('@', '.' . $ext . '.', $name), '.');
        }
        return implode('_', array_map('ucfirst', explode('.', $name)));
    }

    static public function __autoload($class_name)
    {

        $filename = str_replace('_', '/', strtolower($class_name)) . '.php';

        if (file_exists($path = APPLICATION_PATH . '/' . $filename))
        {
            require_once $path;
            return TRUE;
        }

        if (file_exists($path = SYSTEM_APPLICATION_PATH . '/' . $filename))
        {
            require_once $path;
            return TRUE;
        }

        if (file_exists($path = SYSTEM_LIBRARY_PATH . '/agilet/' . $filename))
        {
            require_once $path;
            return TRUE;
        }
        return FALSE;

    }

    static public function getBacktrace()
    {
        $backtrace = array_slice(debug_backtrace(), 1);
        $output = '';
        $output .= 'Stack trace:' . PHP_EOL;

        foreach ($backtrace as $index => $stack)
        {
            // Process args
            $args = array();
            if (!empty($stack['args']))
            {
                foreach ($stack['args'] as $argIndex => $argValue)
                {
                    if (is_object($argValue))
                    {
                        $args[$argIndex] = get_class($argValue);
                    }
                    else
                    if (is_array($argValue))
                    {
                        $args[$argIndex] = 'Array';
                        //substr(print_r($argValue, true), 0, 32);
                    }
                    else
                    if (is_string($argValue))
                    {
                        $args[$argIndex] = "'" . substr($argValue, 0, 32) . (strlen($argValue) > 32 ? '...' : '') . "'";
                    }
                    else
                    {
                        $args[$argIndex] = print_r($argValue, true);
                    }
                }
            }
            // Process message
            $output .= sprintf('#%1$d %2$s(%3$d): %4$s%5$s%6$s(%7$s)', $index, (!empty($stack['file']) ? $stack['file'] : '(unknown file)'), (!empty($stack['line']) ? $stack['line'] : '(unknown line)'), (!empty($stack['class']) ? $stack['class'] : ''), (!empty($stack['type']) ? $stack['type'] : ''), $stack['function'], join(', ', $args)) . PHP_EOL;
        }

        // Throw main in there for the hell of it
        $output .= sprintf('#%1$d {main}', $index + 1);

        return str_replace(ROOT_PATH, '', $output);
    }

    /**
     * handle error
     * @param  int     $errorno
     * @param  string  $errstr
     * @param  string  $errfile
     * @param  int     $errline
     * @param  handle  $errcontext
     */
    static public function errorHandler($errno, $errstr, $errfile = null, $errline = null, array $errcontext = null)
    {
        Logger::inst() -> write(Logger::ERROR, sprintf('[%1$d] %2$s (%3$s) [%4$d]' . PHP_EOL . '%5$s', $errno, $errstr, $errfile, $errline, self::getBacktrace()));
        $level = Logger::INFO;
        $fatal = FALSE;

        switch ($errno)
        {
            case E_USER_NOTICE :
            case E_NOTICE :
                $level = Logger::NOTICE;
                break;
            default :
            case E_USER_WARNING :
            case E_WARNING :
            case E_COMPILE_WARNING :
            case E_CORE_WARNING :
            case E_DEPRECATED :
            case E_STRICT :
            case E_USER_DEPRECATED :
                $level = Logger::WARNING;
                break;
            case E_COMPILE_ERROR :
            case E_CORE_ERROR :
            case E_ERROR :
            case E_PARSE :
            case E_RECOVERABLE_ERROR :
            case E_USER_ERROR :
                $level = Logger::ERR;
                $fatal = TRUE;
                break;
        }

        if ($fatal)
        {
            self::sendFatalError();
        }
        return 1;
    }

    static public function sendFatalError()
    {
        // Clean any previous output from buffer
        while (ob_get_level() > 0)
        {
            ob_end_clean();
        }

        ob_end_clean();
        echo View::render(array(), 'error/fatal.tpl');
        die(1);
    }

    /**
     * handle exception
     * @param Exception $exception
     * @return true/false
     */
    static public function exceptionHandler($exception)
    {
        Logger::inst() -> write(Logger::ERROR, self::getBacktrace() . PHP_EOL . $exception -> getMessage());
        return 0;
    }

    /**
     * handle shutdown
     */
    static public function shutdownHandler()
    {

        /**
         * code here
         */
        Logger::inst() -> flush();
    }

    static public function execute()
    {
        $request = Request::initiator();

        try
        {
            $request -> execute();
        }
        catch(Exception $e)
        {
            $request -> execute('error/404');
        }

        // process with layout container.
        $format = $request -> getParam('format');
        $is_ajax = $request -> isAjax();

        switch($format)
        {
            case 'json' :
            case 'jsonp' :
                return json_encode(array(
                    'html' => $request -> response,
                    'error' => 0,
                    'message' => ''
                ));
                break;
            case 'html' :
            case 'xhtml' :
            case 'xml' :
                return $request -> response;
                break;
            case null :
            default :
                return self::getTemplate() -> execute();
        }
    }

    static public function emit($event)
    {

    }

    static public function getUrl($path, $params = null, $baseUrl = null)
    {
        if(strpos($path, 'http') === 0)
        {
            return $path . ($params? ('?'. http_build_query($params, null,'&')):null);
        }
        
        if (null == $baseUrl)
        {
            $baseUrl = 'http://' . self::$_appDomain . self::$_appUrl;
        }

        $path = $baseUrl . trim($path, '/');

        if ($params)
        {
            return $path . '?' . http_build_query($params, null, '&');
        }

        return $path;
    }

    static function getTemplate()
    {
        if (null == self::$_template)
        {
            self::$_template = new Template;
        }
        return self::$_template;
    }

    /**
     * get current application id
     * @return int
     */
    static public function getAppId()
    {
        return self::$_appId;
    }

    /**
     * set current app Id
     * @param int $appId
     * @return void
     */
    static public function setAppId($appId)
    {
        self::$_appId = (int)$appId;
    }

    static public function getViewer()
    {
        if (null == self::$_viewer)
        {
            $user = null;

            if (isset($_SESSION['uid']) && $id = intval($_SESSION['uid']))
            {
                $user = Mongo_Document::factory('user', $id);
            }
            if (null == $user)
            {
                $user = false;
            }
            self::$_viewer = $user;
        }
        return self::$_viewer;
    }

    /**
     * get general setting as we need.
     * @param string $name
     * @return fixed/array
     */
    static public function getSetting($name)
    {
        $db = Mongo_Database::instance() -> selectCollection('site_settings');
        $result = $db -> findOne(array('_id' => $name));
        if ($result && isset($result['sval']))
        {
            return $result['sval'];
        }
        return $result;
    }

    /**
     * @param string $name
     * @param array $value
     */
    static public function setSetting($name, $value)
    {
        $db = Mongo_Database::instance() -> selectCollection('site_settings');
        if (is_string($value))
        {
            $value = array('sval' => $value);
        }
        $value['_id'] = $name;
        return $db -> save($value);
    }

    static public function redirect($path, $params = null, $host = null)
    {
        $url = self::getUrl($path, $params, $host);
        header('location:' . $url);
        exit ;
    }

    static function __init()
    {
        require 'functions.inc.php';

        if (APPLICATION_ENV == 'development')
        {
            ini_set('display_startup_errors', 1);
            ini_set('display_errors', 1);
            ini_set('error_reporting', E_ALL);
        }

        spl_autoload_register(array(
            'Agilet',
            '__autoload'
        ));

        set_error_handler(array(
            'Agilet',
            'errorHandler'
        ));

        set_exception_handler(array(
            'Agilet',
            'exceptionHandler'
        ));

        register_shutdown_function(array(
            'Agilet',
            'shutdownHandler'
        ));

        session_start();
    }

}
